package com.jochen.core.system

import com.artemis.annotations.Wire
import com.badlogic.gdx.graphics.OrthographicCamera
import com.badlogic.gdx.math.MathUtils
import com.badlogic.gdx.math.Rectangle
import com.badlogic.gdx.math.Vector3
import com.jochen.core.system.input.GestureDetectorSystem

class CameraControlSystem(
    private val bounds: Rectangle,
    private var minZoom: Float = 0.15f,
    private var maxZoom: Float = 0.7f
) : GestureDetectorSystem() {

    @Wire
    private lateinit var camera: OrthographicCamera

    private val targetPosition = Vector3()
    private var targetZoom: Float = minZoom
    private val moveSpeed = 10f
    private val zoomSpeed = 5f

    override fun initialize() {
        camera.position.set(0f, 0f, 0f)
        targetPosition.set(camera.position.x, camera.position.y, 0f)
        camera.zoom = minZoom
        targetZoom = camera.zoom
    }

    override fun pan(x: Float, y: Float, deltaX: Float, deltaY: Float): Boolean{
        targetPosition.add(-deltaX * targetZoom, deltaY * targetZoom, 0f)
        clampTarget()
        return true
    }
    
    override fun zoom(initialDistance: Float, distance: Float): Boolean {
        targetZoom *= (initialDistance / distance)
        clampZoom()
        return true
    }
    
    override fun processSystem() {
        if (!camera.position.epsilonEquals(targetPosition, 0.1f)) {
            camera.position.lerp(targetPosition, moveSpeed * world.delta)
        }

        if (!MathUtils.isEqual(camera.zoom, targetZoom, 0.01f)) {
            camera.zoom = MathUtils.lerp(camera.zoom, targetZoom, zoomSpeed * world.delta)
        }

        camera.update()
    }

    private fun clampTarget() {
        val viewportWidth = camera.viewportWidth * camera.zoom
        val viewportHeight = camera.viewportHeight * camera.zoom

        targetPosition.x = MathUtils.clamp(
            targetPosition.x,
            bounds.x + viewportWidth / 2,
            bounds.x + bounds.width - viewportWidth / 2
        )
        targetPosition.y = MathUtils.clamp(
            targetPosition.y,
            bounds.y + viewportHeight / 2,
            bounds.y + bounds.height - viewportHeight / 2
        )
    }

    private fun clampZoom() {
        targetZoom = MathUtils.clamp(targetZoom, minZoom, maxZoom)
    }
}